from django.shortcuts import render
from django_redis import get_redis_connection
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
import pickle, base64

from carts.serializers import CartSerializer, CartSKUSerializer, CartDeleteSerializer, CartSelectAllSerializer
from goods.models import SKU


class CartSelectAllView(APIView):
    def perform_authentication(self, request):
        """默认此方法在请求分发的时候就会进行认证
        在视图中重写此方法，如果内部直接pass，表示请求分发时，先不要认证，让请求也可以正常访问
        目的：延后它的认证，为了让未登录用户也先能访问视图
        将来自己认证
        """
        pass

    def put(self, request):

        serializer = CartSelectAllSerializer(data=request.data)

        serializer.is_valid(raise_exception=True)

        selected = serializer.validated_data['selected']

        try:
            user = request.user

        except Exception:

            user = None

        if user is not None and user.is_authenticated:  # 判断当前是否是登录用户
            # 登录用户存redis
            # 获取链接redis对象
            redis_conn = get_redis_connection('cart')

            cart = redis_conn.hgetall('cart_%s' % user.id)

            sku_id_list = cart.keys()

            if selected:
                # 全选
                redis_conn.sadd('cart_selected_%s' % user.id, *sku_id_list)

            else:
                # 取消全选
                redis_conn.srem('cart_selected_%s' % user.id, *sku_id_list)

            return Response(data=serializer.data)

        else:

            # 未登录用户存cookies
            # 获取COOKIE中的购物车cart
            cart = request.COOKIES.get('cart')

            if cart:
                cart_dict = pickle.loads(base64.b64decode(cart.encode()))

            else:
                cart_dict = {}

            for sku_dict in cart_dict.values():
                sku_dict['selected'] = selected

            cookie_cart = base64.b64encode(pickle.dumps(cart_dict)).decode()

            response = Response(serializer.data)

            response.set_cookie('cart', cookie_cart)

            return response


class CartView(APIView):
    def perform_authentication(self, request):
        """默认此方法在请求分发的时候就会进行认证
        在视图中重写此方法，如果内部直接pass，表示请求分发时，先不要认证，让请求也可以正常访问
        目的：延后它的认证，为了让未登录用户也先能访问视图
        将来自己认证
        """
        pass

    def post(self, request):
        """增加购物车"""
        # 创建序列化器，进行返序列化
        serializer = CartSerializer(data=request.data)
        # 校验数据
        serializer.is_valid(raise_exception=True)

        sku_id = serializer.validated_data.get('sku_id')

        count = serializer.validated_data.get('count')

        selected = serializer.validated_data.get('selected')

        try:
            user = request.user

        except Exception:

            user = None

        if user is not None and user.is_authenticated:  # 判断当前是否是登录用户
            # 登录用户存redis
            # 获取链接redis对象
            redis_conn = get_redis_connection('cart')
            # 创建管道
            pl = redis_conn.pipeline()
            # {cart_user_idA:{sku_id1:count, sku_id2:count}}
            # {cart_user_idB:{sku_id3:count, sku_id6:count}}
            # hincrby(name, key, amount=1) 此方法表示如果要添加的key在原哈希中不存在就是新增，如果key存在，后面的value就和原有的value相加
            # redis_conn.hincrby('cart_%s' %user.id, sku_id, count)
            pl.hincrby('cart_%s' % user.id, sku_id, count)

            if selected:
                # redis_conn.sadd('cart_selected_%s' %user.id, sku_id)
                pl.sadd('cart_selected_%s' % user.id, sku_id)
            # 执行管道
            pl.execute()

            return Response(data=serializer.data, status=status.HTTP_201_CREATED)

        else:
            # 未登录用户存cookies
            # 获取COOKIE中的购物车cart
            cart = request.COOKIES.get('cart')

            if cart:
                # 把数据转换成str_byte类型
                cart_str_byte = cart.encode()

                # 把str_byte类型转换为dict_byte类型
                cart_dict_byte = base64.b64decode(cart_str_byte)

                # 把dict_byte类型转换为python字典类型
                cart_dict = pickle.loads(cart_dict_byte)

                if sku_id in cart_dict:
                    origin_count = cart_dict[sku_id]["count"]

                    count += origin_count

            else:
                cart_dict = {}

                # 不管有没有这个商品都重新包一下
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected,
            }

            """
            {
            sku_id:{
                'count':count,
                'selected:selected

            }
            """
            # 把cart_dict 转换为dict_byte类型
            cookie_dict_byte = pickle.dumps(cart_dict)

            # 把dict_byte类型转换为str_byte类型
            cookie_str_bytet = base64.b64encode(cookie_dict_byte)

            # 把str_byte转换为字符串
            cookie_str = cookie_str_bytet.decode()

            # 创建响应对象
            response = Response(data=serializer.data, status=status.HTTP_201_CREATED)
            # 设置cookie
            response.set_cookie('cart', cookie_str)

            return response

    def get(self, request):

        # 链接数据库
        redis_conn = get_redis_connection('cart')

        try:
            user = request.user
        except:
            user = None

        if user is not None and user.is_authenticated:
            # 登录用户从redis中获取数据
            # 取出hash数据cart_user_Id {sku:count}
            redis_cart = redis_conn.hgetall('cart_%s' % user.id)

            # 取出set数据cart_selected_user_id {sku1,sku2}
            selected_cart = redis_conn.smembers('cart_selected_%s' % user.id)

            cart_dict = {}

            for sku_id, count in redis_cart.items():
                # python3中redis取出来的数据内部都是bytes类型
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    # True if sku_id in selected_cart else False
                    'selected': sku_id in selected_cart

                }
        else:

            cart = request.COOKIES.get('cart')

            if cart:
                # # 把数据转换成str_byte类型
                # cart_str_byte = cart.encode()
                #
                # # 把str_byte类型转换为dict_byte类型
                # cart_dict_byte = base64.b64decode(cart_str_byte)
                #
                # # 把dict_byte类型转换为python字典类型
                # cart_dict = pickle.loads(cart_dict_byte)
                cart_dict = pickle.loads(base64.b64decode(cart.encode()))

            else:

                cart_dict = {}

        skus = SKU.objects.filter(id__in=cart_dict.keys())

        for sku in skus:
            sku.count = cart_dict[sku.id]['count']
            sku.selected = cart_dict[sku.id]['selected']

        serializer = CartSKUSerializer(skus, many=True)

        return Response(data=serializer.data)

    def put(self, request):

        serializer = CartSerializer(data=request.data)
        # 校验数据
        serializer.is_valid(raise_exception=True)

        sku_id = serializer.validated_data['sku_id']

        count = serializer.validated_data['count']

        selected = serializer.validated_data['selected']

        try:
            user = request.user

        except Exception:

            user = None

        if user is not None and user.is_authenticated:
            # 获取链接对象
            redis_conn = get_redis_connection('cart')
            # 创建管道
            pl = redis_conn.pipeline()

            # 修改
            pl.hset('cart_%s' % user.id, sku_id, count)

            if selected:

                pl.sadd('cart_selected_%s' % user.id, sku_id)

            else:

                pl.srem('cart_selected_%s' % user.id, sku_id)

            pl.execute()

            return Response(serializer.data)  # 获取cookies购物车

        else:
            # 未登录用户存cookies
            # 获取COOKIE中的购物车cart
            cart = request.COOKIES.get('cart')

            if cart:
                # 把数据转换成str_byte类型
                cart_str_byte = cart.encode()

                # 把str_byte类型转换为dict_byte类型
                cart_dict_byte = base64.b64decode(cart_str_byte)

                # 把dict_byte类型转换为python字典类型
                cart_dict = pickle.loads(cart_dict_byte)


            else:
                cart_dict = {}

                # 不管有没有这个商品都重新包一下
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected,
            }

            """
            {
            sku_id:{
                'count':count,
                'selected:selected

            }
            """
            # 把cart_dict 转换为dict_byte类型
            cookie_dict_byte = pickle.dumps(cart_dict)

            # 把dict_byte类型转换为str_byte类型
            cookie_str_bytet = base64.b64encode(cookie_dict_byte)

            # 把str_byte转换为字符串
            cookie_str = cookie_str_bytet.decode()

            # 创建响应对象
            response = Response(data=serializer.data, status=status.HTTP_201_CREATED)
            # 设置cookie
            response.set_cookie('cart', cookie_str)

        return response

    def delete(self, request):

        serializer = CartDeleteSerializer(data=request.data)

        serializer.is_valid(raise_exception=True)

        sku_id = serializer.validated_data['sku_id']

        try:

            user = request.user

        except Exception:

            user = None

        if user is not None and user.is_authenticated:
            # 获取redis链接对象
            redis_conn = get_redis_connection('cart')
            # 创建管道
            pl = redis_conn.pipeline()

            pl.hdel('cart_%s' % user.id, sku_id)

            pl.srem('cart_selected_%s' % user.id, sku_id)

            # 执行管道
            pl.execute()

            return Response(serializer.data)

        else:

            cart = request.COOKIES.get('cart')

            response = Response(status=status.HTTP_204_NO_CONTENT)

            if cart:

                cart_dict = pickle.loads(base64.b64decode(cart.encode()))

                if sku_id in cart_dict:
                    del cart_dict[sku_id]

                    cookie_cart = base64.b64encode(pickle.dumps(cart_dict)).decode()

                    response.set_cookie('cart', cookie_cart)

            return response
